import _ from 'lodash';
import Promise from 'promise';
import logger from '../common/logger';
import * as at from '../common/at';
import * as tools from '../common/tools';
import * as UserProxy from './user';
import * as ZoneProxy from './zone';
import * as AudioProxy from './audio';
import * as ResultMsg from '../constrants/ResultMsg';
import { TopicModel } from '../models';

const fields = '_id title area author_id update_at menu submenu good lock top status';

export function count(appId, conditions, options) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof conditions !== 'object') throw new Error(ResultMsg.NOT_OBJECT);
  if (typeof options !== 'object') options = null;
  conditions.appId = appId;
  return TopicModel.count(conditions).setOptions(options);
}

export function find(appId, conditions, options) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof conditions !== 'object') throw new Error(ResultMsg.NOT_OBJECT);
  if (typeof options !== 'object') options = null;
  conditions.appId = appId;
  conditions.deleted = false;
  const query = TopicModel.find(conditions).select(fields).setOptions(options);
  return query.exec();
}

export function findOne(appId, conditions, options) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof conditions !== 'object') throw new Error(ResultMsg.NOT_OBJECT);
  if (typeof options !== 'object') options = null;
  conditions.appId = appId;

  conditions.deleted = false;
  const query = TopicModel.findOne(conditions).select(fields).setOptions(options);
  return query.exec();
}

export function findOneById(appId, id) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof id !== 'string' && typeof id !== 'object') throw new Error(ResultMsg.NO_ID);
  const query = TopicModel.findOne({appId: appId, _id: id });
  return query.exec();
}

export async function findFullOneById(appId, id) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof id !== 'string' && typeof id !== 'object') throw new Error(ResultMsg.NO_ID);

  try {
    let topic = await TopicModel.findOne({appId: appId, _id: id }).exec();
    if (!topic) return Promise.reject(ResultMsg.DATA_NOT_FOUND);
    topic = topic.toObject();
    topic.linkedContent = at.linkUsers(topic.content);
    topic.create_at = tools.formatDate(topic.create_at);
    topic.update_at = tools.formatDate(topic.update_at);
    const author = await UserProxy.findOneById(appId, topic.author_id);
    topic.author = author;
    const zone = await ZoneProxy.findOneById(appId, topic.zoneId);
    topic.zone = zone;

    let audioListIds = topic.audioList;
    let audioList = [];

    if (audioListIds && audioListIds.length > 0) {
      for (let i = 0; i < audioListIds.length; i ++) {
        let audio = await AudioProxy.findOneById(appId, audioListIds[i]);
        audioList.push(audio);
      }

      topic.audioList = audioList;
    }

    return Promise.resolve(topic);
  } catch (err) {
    logger.error(err);
    return Promise.reject(ResultMsg.DATA_NOT_FOUND);
  }
}

export async function updateLastReply(appId, topicId, replyId) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof topicId !== 'string' && typeof topicId !== 'object') throw new Error(ResultMsg.NO_ID);
  if (typeof replyId !== 'string' && typeof replyId !== 'object') throw new Error(ResultMsg.NO_ID);

  const data = {
    last_reply: replyId,
    last_reply_at: new Date(),
    reply_count: 1,
  };

  const data2 = {
    reply_count: 1,
  };

  try {
    await TopicModel.findByIdAndUpdate(topicId, { data });
    await TopicModel.findByIdAndUpdate(topicId, { $inc: data2 });
  } catch (err) {
    logger.error(err);
  }

  Promise.resolve();
}

export async function reduceTopicCount(appId, topicId, lastReplyId) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof topicId !== 'string' && typeof topicId !== 'object') throw new Error(ResultMsg.NO_ID);
  if (typeof lastReplyId !== 'string' && typeof lastReplyId !== 'object') throw new Error(ResultMsg.NO_ID);

  const data = {
    last_reply: lastReplyId,
    last_reply_at: new Date(),
    reply_count: 1,
  };

  const data2 = {
    reply_count: -1,
  };

  try {
    await TopicModel.findByIdAndUpdate(topicId, { data });
    await TopicModel.findByIdAndUpdate(topicId, { $inc: data2 });
  } catch (err) {
    logger.error(err);
  }

  Promise.resolve();
}

export function create(appId, topic) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof topic !== 'object') throw new Error(ResultMsg.NOT_OBJECT);
  if (typeof topic.zoneId !== 'string' && typeof topic.zoneId !== 'object') throw new Error(ResultMsg.NO_ID);
  if (typeof topic.content !== 'string') throw new Error(ResultMsg.NOT_STRING);

  const data = new TopicModel();
  data.appId = appId;
  data.zoneId = topic.zoneId;
  data.title = topic.title;
  data.area = topic.area
  data.content = topic.content;
  data.advertisingMap = topic.advertisingMap;
  data.menu = topic.menu;
  data.submenu = topic.submenu;
  data.author_id = topic.authorId;
  data.status = topic.status;
  data.mdType = topic.mdType;
  data.tags = topic.tags;
  data.isHtml = topic.isHtml;
  topic.audioList.forEach(function(item) {
    data.audioList.push(item);
  });
  return data.save();
}

export function update(appId, id, data) {
  if (typeof appId !== 'string') throw new Error(ResultMsg.NO_APP_ID);
  if (typeof id !== 'string' && typeof id !== 'object') throw new Error(ResultMsg.NO_ID);
  if (typeof data !== 'object') throw new Error(ResultMsg.NOT_OBJECT);

  delete data._id;
  delete data.create_at;
  delete data.update_at;
  const query = TopicModel.findByIdAndUpdate(id, { $set: data });
  return query.exec();
}
